<?php

declare(strict_types=1);

namespace App\Controller;


use App\Model\User;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\ClientFactory;

abstract class AbstractWeChatController extends AbstractController
{
    protected $wechat_uri = 'https://api.weixin.qq.com';

    /**
     * @var string
     */
    protected $appid;

    /**
     * @var string
     */
    protected $secret;

    protected function __construct()
    {
        parent::__construct();
        $this->appid = env('WeChatAppID');
        $this->secret = env('WeChatAppSecret');
    }

    /**
     * @Inject
     * @var ClientFactory
     */
    protected $clientFactory;

    /**
     * @var array
     */
    protected $user;

    /**
     * 验证参数
     * @return bool
     */
    protected function checkSignature(): bool
    {
        $signature = $this->request->input('signature');
        $timestamp = $this->request->input('timestamp');
        $nonce = $this->request->input('nonce');
        $token = env('WeChatToken');
        $tmpArr = [$token, $timestamp, $nonce];
        sort($tmpArr, SORT_STRING);
        $tmpStr = sha1(implode($tmpArr));
        return $tmpStr === $signature;
    }

    protected function forMiniApp() {
        $this->appid = env('MiniAppID');
        $this->secret = env('MiniAppSecret');
        return $this;
    }

    /**
     * 获取微信用户数据
     * @param $openid
     * @return array
     */
    protected function getUserInfo($openid) :array
    {
        return $this->wechatRequest('cgi-bin/user/info', [
            'access_token' => $this->getAccessToken(),
            'openid' => $openid,
        ]);
    }


    /**
     * 获取accessToken
     * @return string
     */
    protected function getAccessToken() :string
    {
        $token = redis()->get('access_token') ?: '';
        if ($token) {
            return $token;
        }
        $data = $this->wechatRequest('cgi-bin/token');
        if (is_array($data) && isset($data['access_token'])) {
            $token = $data['access_token'];
            redis()->setex('access_token', $data['expires_in'], $token);
        }
        return $token;
    }

    /**
     * 处理消息
     * @param $to   string 接收人
     * @param $from string 发送人
     * @param $content string 消息
     * @return string
     */
    protected function sendTextMsg(string $to, string $from, string $content): string
    {
        $textTpl = "<xml>
        <ToUserName><![CDATA[%s]]></ToUserName>
        <FromUserName><![CDATA[%s]]></FromUserName>
        <CreateTime>%s</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[%s]]></Content>
        </xml>";
        return sprintf($textTpl, $to, $from, time(), $content);
    }

    /**
     * 微信请求
     * @param $uri
     * @param array $query
     * @return array|null
     */
    protected function wechatRequest($uri, array $query = [], $throw_exception = false): ?array
    {
        $option = [
            'base_uri' => $this->wechat_uri,
            'query' => [
                'grant_type' => 'client_credential',
                'appid' => $this->appid,
                'secret' => $this->secret,
                'lang'  =>  'zh_CN',
            ],
        ];
        $option['query'] = array_merge($option['query'], $query);
        $client = $this->clientFactory->create($option);
        try {
            $response = $client->get($uri);
            $result = $response->getBody()->getContents();
            $data = @json_decode($result, true);
            if (isset($data['errcode']) && $throw_exception)  {
                throw new \Exception($data['errmsg'] ?? '服务异常！');
            }
            return $data;
        } catch (GuzzleException $e) {
            if ($throw_exception) throw new \Exception($e->getMessage(), 500);
        }
        return null;
    }

    protected function getInfo($code) {
        return $this->wechatRequest('sns/jscode2session', ['js_code' => $code, 'grant_type' => 'authorization_code'], true);
    }
}
